home *** CD-ROM | disk | FTP | other *** search
/ Nothing but GIFs AGA / Nothing But GIFs.iso / giftrans.lha / GIFTRANS_Original.C < prev    next >
C/C++ Source or Header  |  1995-05-05  |  28KB  |  963 lines

  1. /*
  2. ** GIFtrans v1.12
  3. **
  4. ** Convert any GIF file into a GIF89a
  5. ** Allows for setting the transparent or background color, changing colors,
  6. ** adding or removing comments. Also code to analyze GIF contents.
  7. **
  8. ** Copyright (c) 24.2.94 by Andreas Ley <ley@rz.uni-karlsruhe.de>
  9. **
  10. ** Permission to use, copy, modify, and distribute this software for any
  11. ** purpose and without fee is hereby granted, provided that the above
  12. ** copyright notice appears in all copies. This software is provided "as is"
  13. ** and without any express or implied warranties.
  14. **
  15. ** This program has been tested on a HP9000/715 with HP-UX A.09.05
  16. ** In this environment, neither lint -u nor gcc -Wall produce any messages.
  17. ** It has also been compiled on AIX 3.2 and Solaris 2.3.
  18. ** If you encounter any errors or need to make any changes to port it
  19. ** to another platform, please contact me.
  20. **
  21. ** Known bugs:
  22. **    -B flag won't work if there's an Extension between the Global Color
  23. **    Table and the Image Descriptor (or Graphic Control Extension). If -V
  24. **    has been specified, a Warning Message will be displayed.
  25. **    Will be fixed in 2.0 (if ever)
  26. **    -D option may output changed data instead of original data, use
  27. **    with caution, best only with then -L option.
  28. **
  29. ** Version history
  30. **
  31. ** Version 1.12 - 17.2.95
  32. **    Incorporated dumpcomment by omerzu@quantum.de (Thomas Omerzu)
  33. **    Outputs original version if newer than GIF89a.
  34. **
  35. ** Version 1.11.2 - 14.12.94
  36. **    Incorporated OS/2 port by k.rusch@ieee.org (Klaus Johannes Rusch)
  37. **    Different rgb.txt file for OS/2, setmode replaced by freopen for
  38. **    OS/2 (SAA C) 
  39. **
  40. ** Version 1.11.1 - 11.8.94
  41. **    Allows for use of the -g option without the -B option.
  42. **
  43. ** Version 1.11 - 21.7.94
  44. **    Moved Plain Text Extension to the Extensions section where it belongs.
  45. **    Accept Unknown Extension Labels.
  46. **    Incorporated MS-DOS port by enzo@hk.net (Enzo Michelangeli).
  47. **    Added -o and -e options to redirect stdout and stderr.
  48. **    Added -D debug flag.
  49. **
  50. ** Version 1.10.2 - 22.6.94
  51. **    Support for -DRGBTXT flag.
  52. **
  53. ** Version 1.10.1 - 21.6.94
  54. **    Different rgb.txt file FreeBSD/386BSD.
  55. **
  56. ** Version 1.10 - 19.6.94
  57. **    Added -g option to change a color in the global color table.
  58. **    Added -B option to change the color for the transparent color index.
  59. **
  60. ** Version 1.9.1 - 7.6.94
  61. **    Different rgb.txt files for X11 and Open Windows.
  62. **
  63. ** Version 1.9 - 1.6.94
  64. **    Fixed a bug which caused color names to be rejected.
  65. **
  66. ** Version 1.8 - 30.5.94
  67. **    Accept #rrggbb style arguments.
  68. **    Do nothing if rgb-color not found in GIF.
  69. **
  70. ** Version 1.7 - 16.5.94
  71. **    Added -l option to only list the color table.
  72. **    Added -L option for verbose output without creating a gif.
  73. **    Added -b option to change the background color index.
  74. **    Display all matching color names for color table entries.
  75. **    Fixed a bug which caused bad color names if rgb.txt starts with
  76. **        whitespace.
  77. **    Doesn't use strdup anymore.
  78. **    Fixed =& bug on dec machines.
  79. **
  80. ** Version 1.6 - 5.4.94
  81. **    Added color names recognition.
  82. **
  83. ** Version 1.5 - 15.3.94
  84. **    Added basic verbose output to analyze GIFs.
  85. **
  86. ** Version 1.4 - 8.3.94
  87. **    Fixed off-by-one bug in Local Color table code.
  88. **    Added -c and -C options to add or remove a comment.
  89. **    Transparency is no longer the default.
  90. **
  91. ** Thanx for bug reports, ideas and fixes to
  92. **    patricka@cs.kun.nl (Patrick Atoon)
  93. **    wes@msc.edu (Wes Barris)
  94. **    pmfitzge@ingr.com (Patrick M. Fitzgerald)
  95. **    hoesel@chem.rug.nl (Frans van Hoesel)
  96. **    boardman@jerry.sal.wisc.edu (Dan Boardman)
  97. **    krweiss@chip.ucdavis.edu (Ken Weiss)
  98. **    chuck.musciano@harris.com (Chuck Musciano)
  99. **    heycke@camis.stanford.edu (Torsten Heycke)
  100. **    claw@spacsun.rice.edu (Colin Law)
  101. **    jwalker@eos.ncsu.edu (Joseph C. Walker)
  102. **    Bjorn.Borud@alkymi.unit.no (Bjorn Borud)
  103. **    Christopher.Vance@adfa.oz.au (CJS Vance)
  104. **    pederl@norway.hp.com (Peder Langlo)
  105. **    I.Rutson@bradford.ac.uk (Ian Rutson)
  106. **    Nicolas.Pioch@enst.fr (Nicolas Pioch)
  107. **    john@charles.CS.UNLV.EDU (John Kilburg)
  108. **    enzo@hk.net (Enzo Michelangeli)
  109. **    twv@hpwtwe0.cup.hp.com (Terry von Gease)
  110. **    k.rusch@ieee.org (Klaus Johannes Rusch)
  111. **    omerzu@quantum.de (Thomas Omerzu)
  112. **
  113. ** Original distribution site is
  114. **    ftp://ftp.rz.uni-karlsruhe.de/pub/net/www/tools/giftrans.c
  115. ** A man-page by knordlun@fltxa.helsinki.fi (Kai Nordlund) is at
  116. **    ftp://ftp.rz.uni-karlsruhe.de/pub/net/www/tools/giftrans.1
  117. ** To compile for MS-DOS or OS/2, you need getopt:
  118. **    ftp://ftp.rz.uni-karlsruhe.de/pub/net/www/tools/getopt.c
  119. ** MS-DOS executable can be found at
  120. **    ftp://ftp.rz.uni-karlsruhe.de/pub/net/www/tools/giftrans.exe
  121. ** OS/2 executable can be found at
  122. **    ftp://ftp.rz.uni-karlsruhe.de/pub/net/www/tools/giftrans.os2.exe
  123. ** A template rgb.txt for use with the MS-DOS version can be found at
  124. **    ftp://ftp.rz.uni-karlsruhe.de/pub/net/www/tools/rgb.txt
  125. ** Additional info can be found on
  126. **    http://melmac.corp.harris.com/transparent_images.html
  127. ** The GIF file format is documented in
  128. **    ftp://ftp.uu.net/doc/literary/obi/Standards/Graphics/Formats/gif89a.doc.Z
  129. */
  130.  
  131. #define    X11        /* When using X Window System */
  132. #undef    OPENWIN        /* When using Open Windows */
  133. #undef    X386        /* When using XFree86 with FreeBSD/386BSD */
  134. #undef    OS2        /* When using IBM C/C++ 2.0 */
  135. #ifndef    MSDOS    /* required for TurboC 1.0 */
  136. #undef    MSDOS        /* When using Borland C (maybe MSC too) */
  137. #endif
  138.  
  139. #ifndef OS2_OR_MSDOS
  140. #ifdef OS2
  141. #define OS2_OR_MSDOS
  142. #endif /* OS2 */
  143. #ifdef MSDOS
  144. #define OS2_OR_MSDOS
  145. #endif /* MSDOS */
  146. #endif /* OS2_OR_MSDOS */
  147.  
  148. char copyright[] = "@(#)(c) Copyright 1994 by Andreas Ley (ley@rz.uni-karlsruhe.de)";
  149. char sccsid[] = "@(#)GIFtrans v1.12 - Transpose GIF files";
  150.  
  151. #ifndef RGBTXT
  152. #ifdef X11
  153. #define    RGBTXT    "/usr/lib/X11/rgb.txt"
  154. #else /* X11 */
  155. #ifdef OPENWIN
  156. #define    RGBTXT    "/usr/openwin/lib/rgb.txt"
  157. #else /* OPENWIN */
  158. #ifdef X386
  159. #define    RGBTXT    "/usr/X386/lib/X11/rgb.txt"
  160. #else /* X386 */
  161. #ifdef OS2_OR_MSDOS
  162. #define    RGBTXT    "rgb.txt"
  163. #else /* OS2_OR_MSDOS */
  164. #define    RGBTXT    "";
  165. #endif /* OS2_OR_MSDOS */
  166. #endif /* X386 */
  167. #endif /* OPENWIN */
  168. #endif /* X11 */
  169. #endif /* RGBTXT */
  170.  
  171. #include <stdlib.h>
  172. #include <stdio.h>
  173. #include <string.h>
  174. #include <errno.h>
  175. #ifndef OS2_OR_MSDOS
  176. #include <unistd.h>
  177. #include <ctype.h>
  178. #include <sys/param.h>
  179. #else /* OS2_OR_MSDOS */
  180. #include <fcntl.h>
  181. #ifdef OS2
  182. #include <io.h>
  183. #endif /* OS2 */
  184. #include "getopt.c"
  185. #endif /* OS2_OR_MSDOS */
  186.  
  187. #ifndef MAXPATHLEN
  188. #define MAXPATHLEN 256
  189. #endif /* MAXPATHLEN */
  190.  
  191. #ifndef FALSE
  192. #define    FALSE    (0)        /* This is the naked Truth */
  193. #define    TRUE    (1)        /* and this is the Light */
  194. #endif
  195.  
  196. #define    SUCCESS    (0)
  197. #define    FAILURE    (1)
  198.  
  199. struct entry {
  200.     struct entry    *next;
  201.     char        *name;
  202.     int        red;
  203.     int        green;
  204.     int        blue;
  205.     } *root;
  206.  
  207. #define    NONE    (-1)
  208. #define    OTHER    (-2)
  209. #define    RGB    (-3)
  210.  
  211. struct color {
  212.     int        index;
  213.     int        red;
  214.     int        green;
  215.     int        blue;
  216.     } bc,tc,tn,go,gn;
  217.  
  218. static char    *image,*comment;
  219. static int    skipcomment,list,verbose,output,debug;
  220. static long int    pos;
  221.  
  222. static char    rgbtxt[] = RGBTXT, *rgb = rgbtxt;
  223. static char    true[] = "True";
  224. static char    false[] = "False";
  225.  
  226. #define    readword(buffer)    ((buffer)[0]+256*(buffer)[1])
  227. #define    readflag(buffer)    ((buffer)?true:false)
  228. #define    hex(c)            ('a'<=(c)&&(c)<='z'?(c)-'a'+10:'A'<=(c)&&(c)<='Z'?(c)-'A'+10:(c)-'0')
  229.  
  230.  
  231. void dump(adr,data,len)
  232. long int    adr;
  233. unsigned char    *data;
  234. size_t        len;
  235. {
  236.     int    i;
  237.  
  238.     while (len>0) {
  239.         (void)fprintf(stderr,"%08lx:%*s",adr,(int)((adr%16)*3+(adr%16>8?1:0)),"");
  240.         for (i=adr%16;i<16&&len>0;i++,adr++,data++,len--)
  241.             (void)fprintf(stderr,"%s%02x",i==8?"  ":" ",*data);
  242.         (void)fprintf(stderr,"\n");
  243.     }
  244. }
  245.  
  246.  
  247.  
  248. void writedata(dest,data,len)
  249. FILE        *dest;
  250. unsigned char    *data;
  251. size_t        len;
  252. {
  253.     unsigned char    size;
  254.  
  255.     while (len) {
  256.         size=len<256?len:255;
  257.         (void)fwrite((void *)&size,1,1,dest);
  258.         (void)fwrite((void *)data,(size_t)size,1,dest);
  259.         data+=size;
  260.         len-=size;
  261.     }
  262.     size=0;
  263.     (void)fwrite((void *)&size,1,1,dest);
  264. }
  265.  
  266.  
  267. void skipdata(src)
  268. FILE    *src;
  269. {
  270.     unsigned char    size,buffer[256];
  271.  
  272.     do {
  273.         pos=ftell(src);
  274.         (void)fread((void *)&size,1,1,src);
  275.         if (debug)
  276.             dump(pos,&size,1);
  277.         if (debug) {
  278.             pos=ftell(src);
  279.             (void)fread((void *)buffer,(size_t)size,1,src);
  280.             dump(pos,buffer,(size_t)size);
  281.         }
  282.         else
  283.             (void)fseek(src,(long int)size,SEEK_CUR);
  284.     } while (!feof(src)&&size>0);
  285. }
  286.  
  287.  
  288. void transblock(src,dest)
  289. FILE    *src;
  290. FILE    *dest;
  291. {
  292.     unsigned char    size,buffer[256];
  293.  
  294.     pos=ftell(src);
  295.     (void)fread((void *)&size,1,1,src);
  296.     if (debug)
  297.         dump(pos,&size,1);
  298.     if (output)
  299.         (void)fwrite((void *)&size,1,1,dest);
  300.     pos=ftell(src);
  301.     (void)fread((void *)buffer,(size_t)size,1,src);
  302.     if (debug)
  303.         dump(pos,buffer,(size_t)size);
  304.     if (output)
  305.         (void)fwrite((void *)buffer,(size_t)size,1,dest);
  306. }
  307.  
  308.  
  309. void dumpcomment(src)
  310. FILE    *src;
  311. {
  312.     unsigned char    size,buffer[256];
  313.     size_t i;
  314.  
  315.     pos=ftell(src);
  316.     (void)fread((void *)&size,1,1,src);
  317.     if (debug)
  318.         dump(pos,&size,1);
  319.     (void)fread((void *)buffer,(size_t)size,1,src);
  320.     if (debug)
  321.         dump(pos+1,buffer,(size_t)size);
  322.     for (i=0; i<(size_t)size; i++)
  323.     {
  324.         if (i%60==0)
  325.             (void)putc('\t',stderr);
  326.         if (isprint(buffer[i]))
  327.             (void)putc(buffer[i],stderr);
  328.         else
  329.             (void)fprintf(stderr,"\\%03o",buffer[i]);
  330.         if (i%60==59)
  331.             (void)putc('\n',stderr);
  332.     }
  333.     if (i%60)
  334.         (void)putc('\n',stderr);
  335.     (void)fseek(src,(long int)pos,SEEK_SET);
  336. }
  337.  
  338.  
  339. void transdata(src,dest)
  340. FILE    *src;
  341. FILE    *dest;
  342. {
  343.     unsigned char    size,buffer[256];
  344.  
  345.     do {
  346.         pos=ftell(src);
  347.         (void)fread((void *)&size,1,1,src);
  348.         if (debug)
  349.             dump(pos,&size,1);
  350.         if (output)
  351.             (void)fwrite((void *)&size,1,1,dest);
  352.         pos=ftell(src);
  353.         (void)fread((void *)buffer,(size_t)size,1,src);
  354.         if (debug)
  355.             dump(pos,buffer,(size_t)size);
  356.         if (output)
  357.             (void)fwrite((void *)buffer,(size_t)size,1,dest);
  358.     } while (!feof(src)&&size>0);
  359. }
  360.  
  361.  
  362. int giftrans(src,dest)
  363. FILE    *src;
  364. FILE    *dest;
  365. {
  366.     unsigned char    buffer[3*256],lsd[7],gct[3*256],gce[5];
  367.     unsigned int    cnt,cols,size,gct_size,gct_delay,gce_present;
  368.     struct entry    *rgbptr;
  369.  
  370.  
  371.     /* Header */
  372.     pos=ftell(src);
  373.     (void)fread((void *)buffer,6,1,src);
  374.     if (strncmp((char *)buffer,"GIF",3)) {
  375.         (void)fprintf(stderr,"No GIF file!\n");
  376.         return(1);
  377.     }
  378.     if (verbose) {
  379.         buffer[6]='\0';
  380.         (void)fprintf(stderr,"Header: \"%s\"\n",buffer);
  381.     }
  382.     if (debug)
  383.         dump(pos,buffer,6);
  384.     if (output) {
  385.         if (!strncmp((char *)buffer,"GIF87a",6))
  386.             buffer[4]='9';
  387.         (void)fwrite((void *)buffer,6,1,dest);
  388.     }
  389.  
  390.     /* Logical Screen Descriptor */
  391.     pos=ftell(src);
  392.     (void)fread((void *)lsd,7,1,src);
  393.     if (verbose) {
  394.         (void)fprintf(stderr,"Logical Screen Descriptor:\n");
  395.         (void)fprintf(stderr,"\tLogical Screen Width: %d pixels\n",readword(lsd));
  396.         (void)fprintf(stderr,"\tLogical Screen Height: %d pixels\n",readword(lsd+2));
  397.         (void)fprintf(stderr,"\tGlobal Color Table Flag: %s\n",readflag(lsd[4]&0x80));
  398.         (void)fprintf(stderr,"\tColor Resolution: %d bits\n",(lsd[4]&0x70>>4)+1);
  399.         if (lsd[4]&0x80) {
  400.             (void)fprintf(stderr,"\tSort Flag: %s\n",readflag(lsd[4]&0x8));
  401.             (void)fprintf(stderr,"\tSize of Global Color Table: %d colors\n",2<<(lsd[4]&0x7));
  402.             (void)fprintf(stderr,"\tBackground Color Index: %d\n",lsd[5]);
  403.         }
  404.         if (lsd[6])
  405.             (void)fprintf(stderr,"\tPixel Aspect Ratio: %d (Aspect Ratio %f)\n",lsd[6],((double)lsd[6]+15)/64);
  406.     }
  407.     if (debug)
  408.         dump(pos,lsd,7);
  409.  
  410.     /* Global Color Table */
  411.     gct_delay=FALSE;
  412.     if (lsd[4]&0x80) {
  413.         gct_size=2<<(lsd[4]&0x7);
  414.         pos=ftell(src);
  415.         (void)fread((void *)gct,gct_size,3,src);
  416.         if (go.index==RGB)
  417.             for(cnt=0;cnt<gct_size&&go.index==RGB;cnt++)
  418.                 if (gct[3*cnt]==go.red&&gct[3*cnt+1]==go.green&&gct[3*cnt+2]==go.blue)
  419.                     go.index=cnt;
  420.         if (go.index>=0) {
  421.             if (gn.index>=0) {
  422.                 gn.red=gct[3*gn.index];
  423.                 gn.green=gct[3*gn.index+1];
  424.                 gn.blue=gct[3*gn.index+2];
  425.             }
  426.             gct[3*go.index]=gn.red;
  427.             gct[3*go.index+1]=gn.green;
  428.             gct[3*go.index+2]=gn.blue;
  429.         }
  430.         if (bc.index==RGB)
  431.             for(cnt=0;cnt<gct_size&&bc.index==RGB;cnt++)
  432.                 if (gct[3*cnt]==bc.red&&gct[3*cnt+1]==bc.green&&gct[3*cnt+2]==bc.blue)
  433.                     bc.index=cnt;
  434.         if (bc.index>=0)
  435.             lsd[5]=bc.index;
  436.         if (tc.index==RGB)
  437.             for(cnt=0;cnt<gct_size&&tc.index==RGB;cnt++)
  438.                 if (gct[3*cnt]==tc.red&&gct[3*cnt+1]==tc.green&&gct[3*cnt+2]==tc.blue)
  439.                     tc.index=cnt;
  440.         if (tc.index==OTHER)
  441.             tc.index=lsd[5];
  442.         if (tn.index>=0) {
  443.             tn.red=gct[3*tn.index];
  444.             tn.green=gct[3*tn.index+1];
  445.             tn.blue=gct[3*tn.index+2];
  446.         }
  447.         if (tn.index!=NONE)
  448.             gct_delay=TRUE;
  449.     }
  450.     if (output)
  451.         (void)fwrite((void *)lsd,7,1,dest);
  452.     if (lsd[4]&0x80) {
  453.         if (list||verbose) {
  454.             (void)fprintf(stderr,"Global Color Table:\n");
  455.             for(cnt=0;cnt<gct_size;cnt++) {
  456.                 (void)fprintf(stderr,"\tColor %d: Red %d, Green %d, Blue %d",cnt,gct[3*cnt],gct[3*cnt+1],gct[3*cnt+2]);
  457.                 (void)fprintf(stderr,", #%02x%02x%02x",gct[3*cnt],gct[3*cnt+1],gct[3*cnt+2]);
  458.                 for (rgbptr=root,cols=0;rgbptr;rgbptr=rgbptr->next)
  459.                     if (rgbptr->red==gct[3*cnt]&&rgbptr->green==gct[3*cnt+1]&&rgbptr->blue==gct[3*cnt+2])
  460.                         (void)fprintf(stderr,"%s%s",cols++?", ":" (",rgbptr->name);
  461.                 (void)fprintf(stderr,"%s\n",cols?")":"");
  462.             }
  463.         }
  464.         if (debug)
  465.             dump(pos,gct,gct_size*3);
  466.         if (output&&(!gct_delay))
  467.             (void)fwrite((void *)gct,gct_size,3,dest);
  468.     }
  469.  
  470.     gce_present=FALSE;
  471.     do {
  472.         pos=ftell(src);
  473.         (void)fread((void *)buffer,1,1,src);
  474.         switch (buffer[0]) {
  475.         case 0x2c:    /* Image Descriptor */
  476.             if (verbose)
  477.                 (void)fprintf(stderr,"Image Descriptor:\n");
  478.             (void)fread((void *)(buffer+1),9,1,src);
  479.             /* Write Graphic Control Extension */
  480.             if (tc.index>=0||gce_present) {
  481.                 if (!gce_present) {
  482.                     gce[0]=0;
  483.                     gce[1]=0;
  484.                     gce[2]=0;
  485.                 }
  486.                 if (tc.index>=0) {
  487.                     gce[0]|=0x01;    /* Set Transparent Color Flag */
  488.                     gce[3]=tc.index;    /* Set Transparent Color Index */
  489.                 }
  490.                 else if (gce[0]&0x01)
  491.                     tc.index=gce[3];    /* Remember Transparent Color Index */
  492.                 gce[4]=0;
  493.                 if (tc.index>=0&&(!(buffer[8]&0x80))) { /* Transparent Color Flag set and no Local Color Table */
  494.                     gct[3*tc.index]=tn.red;
  495.                     gct[3*tc.index+1]=tn.green;
  496.                     gct[3*tc.index+2]=tn.blue;
  497.                 }
  498.                 if (output&&gct_delay) {
  499.                     (void)fwrite((void *)gct,gct_size,3,dest);
  500.                     gct_delay=FALSE;
  501.                 }
  502.                 if (output) {
  503.                     (void)fputs("\041\371\004",dest);
  504.                     (void)fwrite((void *)gce,5,1,dest);
  505.                 }
  506.             }
  507.             if (output&&gct_delay) {
  508.                 if (verbose)
  509.                     (void)fprintf(stderr,"Warning: Global Color Table has not been modified as no Transparent Color Index has been set\n");
  510.                 (void)fwrite((void *)gct,gct_size,3,dest);
  511.                 gct_delay=FALSE;
  512.             }
  513.             /* Write Image Descriptor */
  514.             if (verbose) {
  515.                 (void)fprintf(stderr,"\tImage Left Position: %d pixels\n",readword(buffer+1));
  516.                 (void)fprintf(stderr,"\tImage Top Position: %d pixels\n",readword(buffer+3));
  517.                 (void)fprintf(stderr,"\tImage Width: %d pixels\n",readword(buffer+5));
  518.                 (void)fprintf(stderr,"\tImage Height: %d pixels\n",readword(buffer+7));
  519.                 (void)fprintf(stderr,"\tLocal Color Table Flag: %s\n",readflag(buffer[9]&0x80));
  520.                 (void)fprintf(stderr,"\tInterlace Flag: %s\n",readflag(buffer[9]&0x40));
  521.                 if (buffer[9]&0x80) {
  522.                     (void)fprintf(stderr,"\tSort Flag: %s\n",readflag(buffer[9]&0x20));
  523.                     (void)fprintf(stderr,"\tSize of Global Color Table: %d colors\n",2<<(buffer[9]&0x7));
  524.                 }
  525.             }
  526.             if (debug)
  527.                 dump(pos,buffer,10);
  528.             if (output)
  529.                 (void)fwrite((void *)buffer,10,1,dest);
  530.             /* Local Color Table */
  531.             if (buffer[8]&0x80) {
  532.                 size=2<<(buffer[8]&0x7);
  533.                 pos=ftell(src);
  534.                 (void)fread((void *)buffer,size,3,src);
  535.                 if (verbose) {
  536.                     (void)fprintf(stderr,"Local Color Table:\n");
  537.                     for(cnt=0;cnt<size;cnt++)
  538.                         (void)fprintf(stderr,"\tColor %d: Red %d, Green %d, Blue %d\n",cnt,buffer[3*cnt],buffer[3*cnt+1],buffer[3*cnt+2]);
  539.                 }
  540.                 if (tc.index>=0) { /* Transparent Color Flag set */
  541.                     buffer[3*tc.index]=tn.red;
  542.                     buffer[3*tc.index+1]=tn.green;
  543.                     buffer[3*tc.index+2]=tn.blue;
  544.                 }
  545.                 if (debug)
  546.                     dump(pos,buffer,size*3);
  547.                 if (output)
  548.                     (void)fwrite((void *)buffer,size,3,dest);
  549.             }
  550.             /* Table Based Image Data */
  551.             pos=ftell(src);
  552.             (void)fread((void *)buffer,1,1,src);
  553.             if (verbose) {
  554.                 (void)fprintf(stderr,"Table Based Image Data:\n");
  555.                 (void)fprintf(stderr,"\tLZW Minimum Code Size: 0x%02x\n",buffer[0]);
  556.             }
  557.             if (debug)
  558.                 dump(pos,buffer,1);
  559.             if (output)
  560.                 (void)fwrite((void *)buffer,1,1,dest);
  561.             transdata(src,dest);
  562.             gce_present=FALSE;
  563.             break;
  564.         case 0x3b:    /* Trailer */
  565.             if (verbose)
  566.                 (void)fprintf(stderr,"Trailer\n");
  567.             if (debug)
  568.                 dump(pos,buffer,1);
  569.             if (comment&&*comment&&output) {
  570.                 (void)fputs("\041\376",dest);
  571.                 writedata(dest,(unsigned char *)comment,strlen(comment));
  572.             }
  573.             if (output)
  574.                 (void)fwrite((void *)buffer,1,1,dest);
  575.             break;
  576.         case 0x21:    /* Extension */
  577.             (void)fread((void *)(buffer+1),1,1,src);
  578.             switch (buffer[1]) {
  579.             case 0x01:    /* Plain Text Extension */
  580.                 if (output&&gct_delay) {
  581.                     if (verbose)
  582.                         (void)fprintf(stderr,"Warning: Global Color Table has not been modified due to a Plain Text Extension\n");
  583.                     (void)fwrite((void *)gct,gct_size,3,dest);
  584.                     gct_delay=FALSE;
  585.                 }
  586.                 if (verbose)
  587.                     (void)fprintf(stderr,"Plain Text Extension\n");
  588.                 if (debug)
  589.                     dump(pos,buffer,2);
  590.                 if (output)
  591.                     (void)fwrite((void *)buffer,2,1,dest);
  592.                 transblock(src,dest);
  593.                 transdata(src,dest);
  594.                 break;
  595.             case 0xf9:    /* Graphic Control Extension */
  596.                 if (verbose)
  597.                     (void)fprintf(stderr,"Graphic Control Extension:\n");
  598.                 (void)fread((void *)(buffer+2),1,1,src);
  599.                 size=buffer[2];
  600.                 (void)fread((void *)gce,size,1,src);
  601.                 if (verbose) {
  602.                     (void)fprintf(stderr,"\tDisposal Method: %d ",gce[0]&0x1c>>2);
  603.                     switch (gce[0]&0x1c>>2) {
  604.                     case 0:
  605.                         (void)fprintf(stderr,"(no disposal specified)\n");
  606.                         break;
  607.                     case 1:
  608.                         (void)fprintf(stderr,"(do not dispose)\n");
  609.                         break;
  610.                     case 2:
  611.                         (void)fprintf(stderr,"(restore to background color)\n");
  612.                         break;
  613.                     case 3:
  614.                         (void)fprintf(stderr,"(restore to previous)\n");
  615.                         break;
  616.                     default:
  617.                         (void)fprintf(stderr,"(to be defined)\n");
  618.                     }
  619.                     (void)fprintf(stderr,"\tUser Input Flag: %s\n",readflag(gce[0]&0x2));
  620.                     (void)fprintf(stderr,"\tTransparent Color Flag: %s\n",readflag(gce[0]&0x1));
  621.                     (void)fprintf(stderr,"\tDelay Time: %d\n",readword(gce+1));
  622.                     if (gce[0]&0x1)
  623.                         (void)fprintf(stderr,"\tTransparent Color Index: %d\n",gce[3]);
  624.                 }
  625.                 if (debug) {
  626.                     dump(pos,buffer,3);
  627.                     dump(pos+3,gce,size);
  628.                 }
  629.                 pos=ftell(src);
  630.                 (void)fread((void *)buffer,1,1,src);
  631.                 if (debug)
  632.                     dump(pos,buffer,1);
  633.                 gce_present=TRUE;
  634.                 break;
  635.             case 0xfe:    /* Comment Extension */
  636.                 if (verbose)
  637.                 {
  638.                     (void)fprintf(stderr,"Comment Extension\n");
  639.                     dumpcomment(src);
  640.                 }
  641.                 if (debug)
  642.                     dump(pos,buffer,2);
  643.                 if (skipcomment)
  644.                     skipdata(src);
  645.                 else {
  646.                     if (output&&gct_delay) {
  647.                         if (verbose)
  648.                             (void)fprintf(stderr,"Warning: Global Color Table has not been modified due to a Comment Extension\n");
  649.                         (void)fwrite((void *)gct,gct_size,3,dest);
  650.                         gct_delay=FALSE;
  651.                     }
  652.                     if (output)
  653.                         (void)fwrite((void *)buffer,2,1,dest);
  654.                     transdata(src,dest);
  655.                 }
  656.                 break;
  657.             case 0xff:    /* Application Extension */
  658.                 if (output&&gct_delay) {
  659.                     if (verbose)
  660.                         (void)fprintf(stderr,"Warning: Global Color Table has not been modified due to a Application Extension\n");
  661.                     (void)fwrite((void *)gct,gct_size,3,dest);
  662.                     gct_delay=FALSE;
  663.                 }
  664.                 if (verbose)
  665.                     (void)fprintf(stderr,"Application Extension\n");
  666.                 if (debug)
  667.                     dump(pos,buffer,2);
  668.                 if (output)
  669.                     (void)fwrite((void *)buffer,2,1,dest);
  670.                 transblock(src,dest);
  671.                 transdata(src,dest);
  672.                 break;
  673.             default:
  674.                 if (output&&gct_delay) {
  675.                     if (verbose)
  676.                         (void)fprintf(stderr,"Warning: Global Color Table has not been modified due to an unknown Extension\n");
  677.                     (void)fwrite((void *)gct,gct_size,3,dest);
  678.                     gct_delay=FALSE;
  679.                 }
  680.                 if (verbose)
  681.                     (void)fprintf(stderr,"Unknown label: 0x%02x\n",buffer[1]);
  682.                 if (debug)
  683.                     dump(pos,buffer,2);
  684.                 if (output)
  685.                     (void)fwrite((void *)buffer,2,1,dest);
  686.                 transblock(src,dest);
  687.                 transdata(src,dest);
  688.                 break;
  689.             }
  690.             break;
  691.         default:
  692.             (void)fprintf(stderr,"0x%08lx: Unknown extension 0x%02x!\n",ftell(src)-1,buffer[0]);
  693.             if (debug)
  694.                 dump(pos,buffer,1);
  695.             return(1);
  696.         }
  697.     } while (buffer[0]!=0x3b&&!feof(src));
  698.     return(buffer[0]==0x3b?SUCCESS:FAILURE);
  699. }
  700.  
  701.  
  702.  
  703. int getindex(c,arg)
  704. struct color    *c;
  705. char    *arg;
  706. {
  707.     struct entry    *ptr;
  708.  
  709.     if ('0'<=*arg&&*arg<='9')
  710.         c->index=atoi(arg);
  711.     else if (*arg=='#') {
  712.         if (strlen(arg)==4) {
  713.             c->index=RGB;
  714.             c->red=hex(arg[1])<<4;
  715.             c->green=hex(arg[2])<<4;
  716.             c->blue=hex(arg[3])<<4;
  717.         }
  718.         else if (strlen(arg)==7) {
  719.             c->index=RGB;
  720.             c->red=(hex(arg[1])<<4)+hex(arg[2]);
  721.             c->green=(hex(arg[3])<<4)+hex(arg[4]);
  722.             c->blue=(hex(arg[5])<<4)+hex(arg[6]);
  723.         }
  724.         else {
  725.             (void)fprintf(stderr,"%s: illegal color specification: %s\n",image,arg);
  726.             return(FAILURE);
  727.         }
  728.     }
  729.     else {
  730.         for (ptr=root;ptr&&c->index!=RGB;ptr=ptr->next)
  731.             if (!strcmp(ptr->name,arg)) {
  732.                 c->index=RGB;
  733.                 c->red=ptr->red;
  734.                 c->green=ptr->green;
  735.                 c->blue=ptr->blue;
  736.             }
  737.         if (c->index!=RGB) {
  738.             (void)fprintf(stderr,"%s: no such color: %s\n",image,arg);
  739.             return(FAILURE);
  740.         }
  741.     }
  742.     return(SUCCESS);
  743. }
  744.  
  745.  
  746.  
  747. void usage()
  748. {
  749.     (void)fprintf(stderr,"Usage: %s [-t color|-T] [-B color] [-b color] [-g oldcolor=newcolor] [-c comment|-C] [-l|-L|-V] [-o filename] [-e filename] [filename]\n",image);
  750.     (void)fprintf(stderr,"Convert any GIF file into a GIF89a, with the folloing changes possible:\n");
  751.     (void)fprintf(stderr,"-t Specify the transparent color\n");
  752.     (void)fprintf(stderr,"-T Index of the transparent color is the background color index\n");
  753.     (void)fprintf(stderr,"-B Specify the transparent color's new value\n");
  754.     (void)fprintf(stderr,"-b Specify the background color\n");
  755.     (void)fprintf(stderr,"-g Change a color in the global color table\n");
  756.     (void)fprintf(stderr,"-c Add a comment\n");
  757.     (void)fprintf(stderr,"-C Remove old comment\n");
  758.     (void)fprintf(stderr,"-l Only list the color table\n");
  759.     (void)fprintf(stderr,"-L Verbose output of GIFs contents\n");
  760.     (void)fprintf(stderr,"-V Verbose output while converting\n");
  761.     (void)fprintf(stderr,"-o Redirect stdout to a file\n");
  762.     (void)fprintf(stderr,"-e Redirect stderr to a file\n");
  763.     if (*rgb)
  764.         (void)fprintf(stderr,"Colors may be specified as index, as rgb.txt entry or in the #rrggbb form.\n");
  765.     else
  766.         (void)fprintf(stderr,"Colors may be specified as index or in the #rrggbb form.\n");
  767.     exit(1);
  768. }
  769.  
  770.  
  771. int main(argc,argv)
  772. int    argc;
  773. char    *argv[];
  774. {
  775.     int        c;
  776.     extern char    *optarg;
  777.     extern int    optind;
  778.     char        error[2*MAXPATHLEN+14],line[BUFSIZ],*ptr,*nptr,*oname,*ename;
  779.     struct entry    **next;
  780.     FILE        *src;
  781.     int        stat;
  782.  
  783. #ifdef OS2
  784.     ptr=getenv("XFILES");
  785.     if (ptr) {
  786.         rgb=(char *)malloc(strlen(ptr)+strlen(rgbtxt)+2);
  787.         (void)strcpy(rgb,ptr);
  788.         (void)strcat(rgb,"\\");
  789.         (void)strcat(rgb,rgbtxt);
  790.     }
  791. #endif /* OS2 */
  792.  
  793.     image=argv[0];
  794.     root=NULL;
  795.     if (*rgb)
  796.         if ((src=fopen(rgb,"r"))!=NULL) {
  797.             next= &root;
  798.             while (fgets(line,sizeof(line),src)) {
  799.                 *next=(struct entry *)malloc(sizeof(struct entry));
  800.                 for (ptr=line;strchr(" \t",*ptr);ptr++);
  801.                 for (nptr=ptr;!strchr(" \t",*ptr);ptr++);
  802.                 *ptr++='\0';
  803.                 (*next)->red=atoi(nptr);
  804.                 for (;strchr(" \t",*ptr);ptr++);
  805.                 for (nptr=ptr;!strchr(" \t",*ptr);ptr++);
  806.                 *ptr++='\0';
  807.                 (*next)->green=atoi(nptr);
  808.                 for (;strchr(" \t",*ptr);ptr++);
  809.                 for (nptr=ptr;!strchr(" \t",*ptr);ptr++);
  810.                 *ptr++='\0';
  811.                 (*next)->blue=atoi(nptr);
  812.                 for (;strchr(" \t",*ptr);ptr++);
  813.                 for (nptr=ptr;!strchr(" \t\r\n",*ptr);ptr++);
  814.                 *ptr='\0';
  815.                 (void)strcpy((*next)->name=(char *)malloc(strlen(nptr)+1),nptr);
  816.                 (*next)->next=NULL;
  817.                 next= &(*next)->next;
  818.             }
  819.             (void)fclose(src);
  820.         }
  821.         else {
  822. #ifndef OS2_OR_MSDOS
  823.             (void)sprintf(error,"%s: cannot open %s",image,rgb);
  824.             perror(error);
  825.             return(FAILURE);
  826. #else /* OS2_OR_MSDOS */
  827.             *rgb='\0';
  828. #endif
  829.         }
  830.  
  831.     bc.index=NONE;
  832.     tc.index=NONE;
  833.     tn.index=NONE;
  834.     go.index=NONE;
  835.     gn.index=NONE;
  836.     comment=NULL;
  837.     skipcomment=FALSE;
  838.     verbose=FALSE;
  839.     output=TRUE;
  840.     debug=FALSE;
  841.     oname=NULL;
  842.     ename=NULL;
  843.     while ((c=getopt(argc,argv,"t:TB:b:g:c:ClLVDo:e:vh?")) != EOF)
  844.         switch ((char)c) {
  845.         case 'b':
  846.             if (getindex(&bc,optarg))
  847.                 return(FAILURE);
  848.             break;
  849.         case 't':
  850.             if (getindex(&tc,optarg))
  851.                 return(FAILURE);
  852.             break;
  853.         case 'T':
  854.             tc.index=OTHER;
  855.             break;
  856.         case 'B':
  857.             if (getindex(&tn,optarg))
  858.                 return(FAILURE);
  859.             break;
  860.         case 'g':
  861.             if ((ptr=strchr(optarg,'='))!=NULL) {
  862.                 *ptr++='\0';
  863.                 if (getindex(&go,optarg))
  864.                     return(FAILURE);
  865.                 if (getindex(&gn,ptr))
  866.                     return(FAILURE);
  867.             }
  868.             else
  869.                 usage();
  870.             break;
  871.         case 'c':
  872.             comment=optarg;
  873.             break;
  874.         case 'C':
  875.             skipcomment=TRUE;
  876.             break;
  877.         case 'l':
  878.             list=TRUE;
  879.             output=FALSE;
  880.             break;
  881.         case 'L':
  882.             verbose=TRUE;
  883.             output=FALSE;
  884.             break;
  885.         case 'V':
  886.             verbose=TRUE;
  887.             break;
  888.         case 'D':
  889.             debug=TRUE;
  890.             break;
  891.         case 'o':
  892.             oname=optarg;
  893.             break;
  894.         case 'e':
  895.             ename=optarg;
  896.             break;
  897.         case 'v':
  898.             (void)fprintf(stderr,"%s\n",sccsid+4);
  899.             (void)fprintf(stderr,"%s\n",copyright+4);
  900.             return(0);
  901.         case 'h':
  902.             (void)fprintf(stderr,"%s\n",sccsid+4);
  903.             (void)fprintf(stderr,"%s\n",copyright+4);
  904.         case '?':
  905.             usage();
  906.         }
  907.     if (optind+1<argc||(bc.index==NONE&&tc.index==NONE&&tn.index==NONE&&gn.index==NONE&&comment==NULL&&!skipcomment&&!list&&!verbose))
  908.         usage();
  909.  
  910.     if (oname&&freopen(oname,"wb",stdout)==NULL) {
  911.         (void)sprintf(error,"%s: cannot open %s",image,oname);
  912.         perror(error);
  913.         return(FAILURE);
  914.     }
  915.  
  916.     if (ename&&freopen(ename,"wb",stderr)==NULL) {
  917.         (void)sprintf(error,"%s: cannot open %s",image,ename);
  918.         perror(error);
  919.         return(FAILURE);
  920.     }
  921.  
  922. #ifdef OS2_OR_MSDOS
  923. #ifdef MSDOS
  924.     if(oname==NULL&&(stdout->flags&_F_TERM)==0&&setmode(fileno(stdout),O_BINARY)!=0) {
  925. #endif /* MSDOS */
  926. #ifdef OS2
  927.     if(oname==NULL&&!freopen("", "wb", stdout)) {
  928. #endif /* OS2 */
  929.         (void)fprintf(stderr,"%s: can't set stdout's mode to binary\n",image);
  930.         exit(2);
  931.     }
  932. #ifdef MSDOS
  933.     if(optind==argc&&(stdin->flags&_F_TERM)==0&&setmode(fileno(stdin),O_BINARY)) {
  934. #endif /* MSDOS */
  935. #ifdef OS2
  936.     if(optind==argc&&!freopen("", "rb", stdin)) {
  937. #endif /* OS2 */
  938.         (void)fprintf(stderr,"%s: can't set stdin's mode to binary\n",image);
  939.         exit(2);
  940.     }
  941. #endif /* OS2_OR_MSDOS */
  942.  
  943.     if (optind<argc)
  944.         if (strcmp(argv[optind],"-"))
  945.             if ((src=fopen(argv[optind],"rb"))!=NULL) {
  946.                 stat=giftrans(src,stdout);
  947.                 (void)fclose(src);
  948.             }
  949.             else {
  950.                 (void)sprintf(error,"%s: cannot open %s",image,argv[optind]);
  951.                 perror(error);
  952.                 return(FAILURE);
  953.             }
  954.         else
  955.             stat=giftrans(stdin,stdout);
  956.     else
  957.         stat=giftrans(stdin,stdout);
  958.  
  959.     (void)fclose(stdout);
  960.     (void)fclose(stderr);
  961.     return(stat);
  962. }
  963.